package com.donger.mes.system.mes.work;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.donger.mes.system.base.entity.MesBaseBom;
import com.donger.mes.system.base.entity.MesBaseMaterial;
import com.donger.mes.system.base.entity.MesBaseWorkCenter;
import com.donger.mes.system.base.mapper.MesBaseBomMapper;
import com.donger.mes.system.base.mapper.MesBaseMaterialMapper;
import com.donger.mes.system.base.mapper.MesBaseWorkCenterMapper;
import com.donger.mes.system.mes.dto.WorkCenterMatPlatformDTO;
import com.donger.mes.system.mes.dto.WorkDTO;
import com.donger.mes.system.mes.entity.WorkCenterMat;
import com.donger.mes.system.mes.entity.WorkCenterPlan;
import com.donger.mes.system.mes.entity.WorkCenterProduct;
import com.donger.mes.system.mes.enums.PlanStatusEnum;
import com.donger.mes.system.mes.service.MesProducePlanDayService;
import com.donger.mes.system.mes.service.WorkCenterMatService;
import com.donger.mes.system.mes.service.WorkCenterProductService;
import com.donger.common.core.utils.BizException;
import com.donger.mes.utils.mes.MesUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * 单品码
 * @author aeizzz
 */
@Component(value = "singleCode")
@AllArgsConstructor
public class SingleCodeWorkHandle implements WorkHandle{

    private final MesBaseBomMapper mesBaseBomMapper;

    private final MesBaseWorkCenterMapper mesBaseWorkCenterMapper;

    private final WorkCenterMatService workCenterMatService;

    private final MesBaseMaterialMapper mesBaseMaterialMapper;

    private final WorkCenterProductService workCenterProductService;

    /**
     * 处理逻辑
     * @param workCenterPlan
     * @param workDTO
     * @return
     */
    @Override
    public WorkCenterPlan execute(WorkCenterPlan workCenterPlan, WorkDTO workDTO) {
        // 校验数据
        this.checkData(workCenterPlan,workDTO);
        /**
         *  物料倒冲
         */
        // 当前工作中心产成品信息
        MesBaseWorkCenter mesBaseWorkCenter = Optional.ofNullable(mesBaseWorkCenterMapper.selectOne(Wrappers.<MesBaseWorkCenter>lambdaQuery()
                .eq(MesBaseWorkCenter::getCode, workCenterPlan.getWorkCenterCode())
        )).orElseThrow(() -> new BizException("工作中心为空"));

        MesBaseMaterial mesBaseMaterial = Optional.ofNullable(mesBaseMaterialMapper.selectOne(Wrappers.<MesBaseMaterial>lambdaQuery()
                .eq(MesBaseMaterial::getMatCode, workCenterPlan.getProductCode()))).orElseThrow(() -> new BizException("产成品物料基础信息为空"));

        List<MesBaseBom> mesBaseBomList;

        if("bom".equals(mesBaseWorkCenter.getBackflushMode())){
            mesBaseBomList =  mesBaseBomMapper.selectList(Wrappers.<MesBaseBom>lambdaQuery()
                    .eq(MesBaseBom::getParentCode, mesBaseMaterial.getMatCode())
            );
        }else{
            throw new BizException("暂不支持根据输入物料报工");
        }
        // 倒冲数量为生产数量减返工返修数量
        this.backflush(workCenterPlan,mesBaseBomList,workDTO.getNum() - workDTO.getUnqualifiedNum());
        // 更新对应的完成数量
        workCenterPlan.setSuccessCount(workCenterPlan.getSuccessCount() + workDTO.getNum());
        if(workCenterPlan.getSuccessCount() >= workCenterPlan.getProductCount()){
            workCenterPlan.setStatusCode(PlanStatusEnum.FINISH.getType());
            workCenterPlan.setStatus(PlanStatusEnum.FINISH.getDescription());
        }




        /**
         * 记录报工日志信息
         *
         *
         *
         *
         */



        /**
         * 报工
         */
        // 完成倒冲以后进行保存数据
        this.produce(mesBaseWorkCenter.getType(),workCenterPlan,workDTO,mesBaseMaterial);

        return workCenterPlan;
    }

    /**
     * 预处理各种校验情况
     * 如果通用则最好在上层进行处理
     * @param workCenterPlan
     * @param workDTO
     */
    @Override
    public void checkData(WorkCenterPlan workCenterPlan, WorkDTO workDTO) {
        if(workCenterPlan.getMode().equals("input")){
            throw new BizException("该工作中心不能进行报工");
        }

    }

    /**
     * 物料进行倒冲
     * 根据bom 删除对应物料的信息并保存倒冲记录
     * @param materialList bom 数据
     * @param produceNum 生产数量
     */
    @Override
    @Transactional
    public void backflush(WorkCenterPlan workCenterPlan,List<MesBaseBom> materialList, Long produceNum) {
        if(CollUtil.isEmpty(materialList)){
            throw new BizException("倒冲物料BOM为空,不能报工");
        }

        List<WorkCenterMatPlatformDTO> workCenterMatPlatformDTOS = workCenterMatService
                .listGroupByWorkCenter(workCenterPlan.getPlanCode());

        List<WorkCenterMat> updateMatList = new ArrayList<>();
        List<WorkCenterMat> deleteMatList = new ArrayList<>();

        materialList.forEach(item -> {

            Float totalNeedMatNum = item.getCount() * produceNum;

            String matCode = item.getMatCode();
            List<WorkCenterMatPlatformDTO> collect = workCenterMatPlatformDTOS.stream()
                    .filter(workCenterMatPlatformDTO -> workCenterMatPlatformDTO.getMatCode().equals(matCode)).collect(Collectors.toList());
            if(CollUtil.isEmpty(collect)){
                throw new BizException("工作中心无对应物料"+ item.getMatCode());
            }
            WorkCenterMatPlatformDTO workCenterMatPlatformDTO = collect.get(0);
            if(workCenterMatPlatformDTO.getNum() < totalNeedMatNum){
                throw new BizException("工作中心剩余物料不足" + item.getMatName() + "剩余物料" + workCenterMatPlatformDTO.getNum().toString());
            }

            LambdaQueryWrapper<WorkCenterMat> queryWrapper = Wrappers.<WorkCenterMat>lambdaQuery()
                    .eq(WorkCenterMat::getMatCode, item.getMatCode())
                    .eq(WorkCenterMat::getPlanCode,workCenterPlan.getPlanCode())
                    .gt(WorkCenterMat::getCurrentNumber,0)
                    .orderByAsc(WorkCenterMat::getCreatedTime);

            List<WorkCenterMat> workCenterMats = workCenterMatService.list(queryWrapper);

            for (WorkCenterMat materialItem: workCenterMats){
                Float surplusNum = materialItem.getCurrentNumber();
                if(surplusNum <=0){
                    continue;
                }

                // 余量减去需要的的总数，如果本条记录余量还有剩余，倒冲减一下，更新余量
                if (surplusNum - totalNeedMatNum > 0) {
                    materialItem.setCurrentNumber(surplusNum - totalNeedMatNum);
                    updateMatList.add(materialItem);
                    break;
                } else {
                    deleteMatList.add(materialItem);
                }
                totalNeedMatNum -= surplusNum;
                // 如果本次需要消耗的原材料已经被倒冲完了，退出循环
                if (totalNeedMatNum <= 0) {
                    break;
                }
            }
        });

        // 统一处理对应数据
        workCenterMatService.updateBatchById(updateMatList);
        workCenterMatService.deleteBatchById(deleteMatList);
    }

    /**
     * 处理订单是否完成
     * 产成品报工的数据如何存储
     * @param type 报工模式  下级使用，  生成产成品数据 供成品入库还是半成品入库  目标为线边仓库
     * @param workCenterPlan
     * @param workDTO
     */
    @Override
    public void produce(String type, WorkCenterPlan workCenterPlan,WorkDTO workDTO,MesBaseMaterial mesBaseMaterial) {
        // 半成品模式
        if("semi".equals(type)){

            WorkCenterMat workCenterMat = workCenterMatService.queryByBarcodeAndSupplier(workCenterPlan.getWorkCenterCode(),workDTO.getPackageCode(),"供应商编码",workCenterPlan.getPlanCode());

            if(workCenterMat == null){
                workCenterMat = new WorkCenterMat();
                workCenterMat.setWorkCenterCode(workCenterPlan.getWorkCenterCode());
                workCenterMat.setWorkCenterName(workCenterPlan.getName());
                workCenterMat.setPlanCode(workCenterPlan.getPlanCode());
                workCenterMat.setMatBarcode(workDTO.getPackageCode());
                workCenterMat.setMatCode(mesBaseMaterial.getMatCode());
                workCenterMat.setMatName(mesBaseMaterial.getMatName());
                workCenterMat.setSupplierCode("供应商编码");
                workCenterMat.setSupplierName("供应商名称");
                workCenterMat.setCurrentNumber(Float.valueOf(workDTO.getNum()));
                workCenterMat.setNum(Float.valueOf(workDTO.getNum()));
            }
            // 需要先查询是否已经存在，如果有则是更新 没有则新增 条码相同
            // 产成品报工的数据如何存储
            workCenterMat.setCurrentNumber(workCenterMat.getCurrentNumber() + Float.valueOf(workDTO.getNum()));
            workCenterMat.setNum(workCenterMat.getNum() + Float.valueOf(workDTO.getNum()));
            // 供应商信息为当用组织信息，，应该在配置文件进行配置
            workCenterMatService.save(workCenterMat);
        }else if("finish".equals(type)){
            // 根据客户物料的配置
            WorkCenterProduct workCenterProduct = new WorkCenterProduct();
            workCenterProduct.setBanci(MesUtils.calcBanciByDate());
            workCenterProduct.setPlanCode(workCenterPlan.getPlanCode());
            workCenterProduct.setWorkCenterPlanCode(workCenterPlan.getWorkCenterPlanCode());
            workCenterProduct.setBoxCode(workDTO.getPackageCode());
            workCenterProduct.setBatch("");
            workCenterProduct.setPackageCode(workDTO.getPackageCode());
            workCenterProduct.setIsolate(workDTO.getIsolate());
            workCenterProduct.setProductCode(mesBaseMaterial.getMatCode());
            workCenterProduct.setProductName(mesBaseMaterial.getMatName());
//            workCenterProduct.setType();
//            workCenterProduct.setEmployeeCode();

            workCenterProduct.setUnqualifiedNum(workDTO.getUnqualifiedNum());
            workCenterProduct.setNum(workDTO.getNum());
            workCenterProductService.save(workCenterProduct);
        }else {
            throw new BizException("报工模式选择不正确，不能报工");
        }
    }
}
